package com.xnyzc.lhy.resource.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.MDC;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 极光推送
 * </p>
 *
 * @author liuju
 * @since 2019-09-20
 */
@Slf4j
@Service("httpClientService")
public class HttpClientService {
	private static final String CONTENT_TYPE = "Content-Type";
	private static final String CONTENT_TYPE_JSON_UTF_8 = "application/json";
	private static final String CSBC_HTTP_SEQ = "t_seq";
	private static final int CSBC_HTTP_SEQ_LENGTH = 16;

	public CsbcHttpResponse get(String url) throws Exception {
		return get(url, null, null, null);
	}

	public CsbcHttpResponse get(String url, String randomSeq) throws Exception {
		return get(url, null, randomSeq, null);
	}

	public CsbcHttpResponse get(String url, List<Map<String, String>> reqHeadersList, String randomSeq,
			List<NameValuePair> params) throws Exception {
		long startTime = System.currentTimeMillis();

		CloseableHttpClient httpclient = HttpClients.createDefault();
		/*
		 * if (StringUtils.isEmpty(randomSeq)) { randomSeq = createHttpRandomSeq(); }
		 */
		HttpGet httpGet = null;
		if (null == params || params.size() == 0) {
			httpGet = new HttpGet(url);
		} else {
			String paramStr = EntityUtils.toString(new UrlEncodedFormEntity(params, Consts.UTF_8));
			httpGet = new HttpGet(url + "?" + paramStr);
		}

		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(100000).setConnectTimeout(10000)
				.setConnectionRequestTimeout(10000).build();
		httpGet.setConfig(requestConfig);

		httpGet.addHeader(CSBC_HTTP_SEQ, randomSeq);
		if (null != reqHeadersList && (reqHeadersList.size() != 0)) {
			for (Map<String, String> headerMap : reqHeadersList) {
				for (String key : headerMap.keySet()) {
					httpGet.addHeader(key, headerMap.get(key));
				}
			}
		}
		showReqInfoLog(httpGet);

		CloseableHttpResponse response = httpclient.execute(httpGet);

		String respBodyCont = "";
		if(null != response.getEntity()) {
			respBodyCont = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
		}

		showRespInfoLog(response, respBodyCont);

		response.close();
		httpGet.releaseConnection();
		httpGet.abort();
		httpclient.close();

		log.info("[REQ_T] {}ms!", System.currentTimeMillis() - startTime);

		return createCsbcHttpResponse(response, respBodyCont);
	}

	public CsbcHttpResponse post(String url, String reqJsonBody) throws Exception {
		return post(url, null, reqJsonBody, null);
	}

	public CsbcHttpResponse post(String url, List<Map<String, String>> reqHeadersList, String reqJsonBody)
			throws Exception {
		return post(url, reqHeadersList, reqJsonBody, null);
	}

	public CsbcHttpResponse post(String url, List<Map<String, String>> reqHeadersList, String reqJsonBody,
			String randomSeq) throws Exception {

		CloseableHttpClient httpclient = HttpClients.createDefault();
		/*
		 * if (StringUtils.isEmpty(randomSeq)) { randomSeq = createHttpRandomSeq(); }
		 */

		HttpPost httpPost = new HttpPost(url);

		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(100000).setConnectTimeout(10000)
				.setConnectionRequestTimeout(10000).build();
		httpPost.setConfig(requestConfig);

		httpPost.addHeader(CONTENT_TYPE, CONTENT_TYPE_JSON_UTF_8);
		httpPost.addHeader(CSBC_HTTP_SEQ, randomSeq);
		if (null != reqHeadersList && (reqHeadersList.size() != 0)) {
			for (Map<String, String> headerMap : reqHeadersList) {
				for (String key : headerMap.keySet()) {
					httpPost.addHeader(key, headerMap.get(key));
				}
			}
		}

		HttpEntity reqEntity = new StringEntity(reqJsonBody, ContentType.APPLICATION_JSON);
		httpPost.setEntity(reqEntity);
		String reqBodyContent = EntityUtils.toString(httpPost.getEntity(), Consts.UTF_8);
		showReqInfoLog(httpPost, reqBodyContent);

		CloseableHttpResponse response = httpclient.execute(httpPost);

		String respBodyCont = "";
		if(null != response.getEntity()) {
			respBodyCont = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
		}

		showRespInfoLog(response, respBodyCont);

		response.close();
		httpPost.releaseConnection();
		httpPost.abort();
		httpclient.close();

		return createCsbcHttpResponse(response, respBodyCont);
	}

	public CsbcHttpResponse put(String url, String reqJsonBody) throws Exception {
		return put(url, null, reqJsonBody, null);
	}

	public CsbcHttpResponse put(String url, List<Map<String, String>> reqHeadersList, String reqJsonBody)
			throws Exception {
		return put(url, reqHeadersList, reqJsonBody, null);
	}

	public CsbcHttpResponse put(String url, List<Map<String, String>> reqHeadersList, String reqJsonBody,
			String randomSeq) throws Exception {

		CloseableHttpClient httpclient = HttpClients.createDefault();
		if (StringUtils.isEmpty(randomSeq)) {
			randomSeq = createHttpRandomSeq();
		}

		HttpPut httpPut = new HttpPut(url);

		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(100000).setConnectTimeout(10000)
				.setConnectionRequestTimeout(10000).build();
		httpPut.setConfig(requestConfig);

		httpPut.addHeader(CONTENT_TYPE, CONTENT_TYPE_JSON_UTF_8);
		httpPut.addHeader(CSBC_HTTP_SEQ, randomSeq);
		if (null != reqHeadersList && (reqHeadersList.size() != 0)) {
			for (Map<String, String> headerMap : reqHeadersList) {
				for (String key : headerMap.keySet()) {
					httpPut.addHeader(key, headerMap.get(key));
				}
			}
		}

		HttpEntity reqEntity = new StringEntity(reqJsonBody, ContentType.APPLICATION_JSON);
		httpPut.setEntity(reqEntity);
		String reqBodyContent = EntityUtils.toString(httpPut.getEntity(), Consts.UTF_8);
		showReqInfoLog(httpPut, reqBodyContent);

		CloseableHttpResponse response = httpclient.execute(httpPut);

		String respBodyCont = "";
		if(null != response.getEntity()) {
			respBodyCont = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
		}

		showRespInfoLog(response, respBodyCont);

		response.close();
		httpPut.releaseConnection();
		httpPut.abort();
		httpclient.close();

		return createCsbcHttpResponse(response, respBodyCont);
	}

	public CsbcHttpResponse delete(String url) throws Exception {
		return delete(url, null, null);
	}

	public CsbcHttpResponse delete(String url, String randomSeq) throws Exception {
		return delete(url, null, randomSeq);
	}

	public CsbcHttpResponse delete(String url, List<Map<String, String>> reqHeadersList, String randomSeq)
			throws Exception {

		CloseableHttpClient httpclient = HttpClients.createDefault();
		if (StringUtils.isEmpty(randomSeq)) {
			randomSeq = createHttpRandomSeq();
		}

		HttpDelete httpDelete = new HttpDelete(url);

		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(10000)
				.setConnectionRequestTimeout(10000).build();
		httpDelete.setConfig(requestConfig);

		httpDelete.addHeader(CSBC_HTTP_SEQ, randomSeq);
		if (null != reqHeadersList && (reqHeadersList.size() != 0)) {
			for (Map<String, String> headerMap : reqHeadersList) {
				for (String key : headerMap.keySet()) {
					httpDelete.addHeader(key, headerMap.get(key));
				}
			}
		}
		showReqInfoLog(httpDelete);

		CloseableHttpResponse response = httpclient.execute(httpDelete);

		String respBodyCont = "";
		if(null != response.getEntity()) {
			respBodyCont = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
		}

		showRespInfoLog(response, respBodyCont);

		response.close();
		httpDelete.releaseConnection();
		httpDelete.abort();
		httpclient.close();

		return createCsbcHttpResponse(response, respBodyCont);
	}

	private CsbcHttpResponse createCsbcHttpResponse(CloseableHttpResponse response, String respBodyCont) {
		Header[] respAllHeaders = response.getAllHeaders();
		List<Map<String, String>> respHeadersList = new ArrayList<Map<String, String>>();
		if (null != respAllHeaders && respAllHeaders.length > 0) {
			Map<String, String> respHeader = new HashMap<String, String>();
			for (Header tempHeader : respAllHeaders) {
				respHeader.put(tempHeader.getName(), tempHeader.getValue());
				respHeadersList.add(respHeader);
			}
		}

		return new CsbcHttpResponse(response.getStatusLine().getStatusCode(), respHeadersList, respBodyCont);
	}

	private void showReqInfoLog(HttpGet httpGet) {

		log.info("[REQ_S] {}", httpGet.getRequestLine());

		appendHeader(httpGet.getAllHeaders(), "[REQ_H] {}", "[REQ_H] is empty!");
	}

	private void appendHeader(Header[] allHeaders, String s, String s2) {
		Header[] reqHeaderArray = allHeaders;
		StringBuffer reqHeader = new StringBuffer();
		for (Header tempHeader : reqHeaderArray) {
			reqHeader.append(tempHeader.getName());
			reqHeader.append(":");
			reqHeader.append(tempHeader.getValue());
			reqHeader.append(";");
		}
		if (!StringUtils.isEmpty(reqHeader.toString())) {
			log.info(s, reqHeader.toString());
		} else {
			log.info(s2);
		}
	}

	private void showReqInfoLog(HttpPost httpPost, String reqBodyContent) {

		log.info("[REQ_S] {}", httpPost.getRequestLine());

		appendHeader(httpPost.getAllHeaders(), "[REQ_H] {}", "[REQ_H] is empty!");

		if (!StringUtils.isEmpty(reqBodyContent)) {
			log.info("[REQ_B] {}", reqBodyContent);
		} else {
			log.info("[REQ_B] is empty!");
		}
	}

	private void showReqInfoLog(HttpPut httpPut, String reqBodyContent) {

		log.info("[REQ_S] {}", httpPut.getRequestLine());

		appendHeader(httpPut.getAllHeaders(), "[REQ_H] {}", "[REQ_H] is empty!");

		if (!StringUtils.isEmpty(reqBodyContent)) {
			log.info("[REQ_B] {}", reqBodyContent);
		} else {
			log.info("[REQ_B] is empty!");
		}
	}

	private void showReqInfoLog(HttpDelete httpDelete) {

		log.info("[REQ_S] {}", httpDelete.getRequestLine());

		appendHeader(httpDelete.getAllHeaders(), "[REQ_H] {}", "[REQ_H] is empty!");
	}

	private void showRespInfoLog(CloseableHttpResponse response, String respBodyCont) {

		log.info("[RSP_S] {}", response.getStatusLine());

		appendHeader(response.getAllHeaders(), "[RSP_H] {}", "[RSP_H] is empty!");

		if (!StringUtils.isEmpty(respBodyCont)) {
			log.info("[RSP_B] {}", respBodyCont);
		} else {
			log.info("[RSP_B] is empty!");
		}
	}

	private String createHttpRandomSeq() {
		String seqFromMdc = MDC.get("REQ_ID");
		if (StringUtils.isEmpty(seqFromMdc)) {
			return RandomStringUtils.randomNumeric(CSBC_HTTP_SEQ_LENGTH);
		} else {
			return seqFromMdc;
		}
	}
}
